<template>
    <!-- 组态主界面 -->
    <div class="topo-main" ref="topoMainRef">
        <div class="scale-button">
            <el-button icon="el-icon-zoom-in" size="small" :disabled="scale >= 5" @click="() => (scale += 1)" />
            <el-select v-model="scale" style="width: 100px" size="mini">
                <el-option :value="1" label="自适应" />
                <el-option :value="2" label="200%" />
                <el-option :value="3" label="300%" />
                <el-option :value="4" label="400%" />
                <el-option :value="5" label="500%" />
            </el-select>
            <el-button icon="el-icon-zoom-out" size="small" :disabled="scale <= 1" @click="() => (scale -= 1)" />
        </div>
        <div class="topo-main-header" ref="topoMain">
            <vue-ruler-tool :parent="true" :is-scale-revise="true" :is-hot-key="false" ref="rulerTool">
                <div
                    tabindex="0"
                    id="surface-edit-layer"
                    class="topo-layer 2"
                    :class="{ 'topo-layer-view-selected': selectedIsLayer }"
                    :style="layerStyle"
                    @click="onLayerClick($event)"
                    @mouseup="onLayerMouseup($event)"
                    @mousemove="onLayerMousemove($event)"
                    @mousedown="onLayerMousedown($event)"
                    @keyup.delete="removeItem($event)"
                    @dragover.prevent
                    @drop="onDrop"
                    @contextmenu.prevent="onContextmenu"
                    @keydown.ctrl.67.stop="copyItem"
                    @keydown.ctrl.86.stop="pasteItem"
                    @keydown.ctrl.90.stop="revoke"
                    @keydown.ctrl.89.stop="recovery"
                    ref="imageTofile"
                >
                    <template v-for="(component, index) in configData.components">
                        <div
                            tabindex="0"
                            class="topo-layer-view"
                            :class="{ 'topo-layer-view-selected': selectedComponentMap[component.identifier] == undefined ? false : true }"
                            @click.stop="clickComponent(index, component, $event)"
                            @mousedown.stop="controlMousedown(component, $event, index)"
                            @keyup.delete="removeItem($event)"
                            @keydown.up.exact.prevent="moveItems('up')"
                            @keydown.right.exact.prevent="moveItems('right')"
                            @keydown.down.exact.prevent="moveItems('down')"
                            @keydown.left.exact.prevent="moveItems('left')"
                            @keydown.ctrl.67.stop="copyItem"
                            @keydown.ctrl.86.stop="pasteItem"
                            @keydown.ctrl.90.stop="revoke"
                            @keydown.ctrl.89.stop="recovery"
                            :style="{
                                left: component.style.position.x + 'px',
                                top: component.style.position.y + 'px',
                                width: component.style.position.w + 'px',
                                height: component.style.position.h + 'px',
                                backgroundColor: component.type == 'flow-bar' || component.type == 'flow-bar-dynamic' ? 'transparent' : component.style.backColor,
                                zIndex: component.style.zIndex,
                                transform: component.style.transformType,
                                opacity: component.style.opacity,
                                'border-radius': component.style.borderRadius + 'px',
                                'box-shadow': '0 0 ' + component.style.boxShadowWidth + 'px 0 ' + component.style.boxShadowColor,
                            }"
                            v-if="(component.style.visible == undefined ? true : component.style.visible) && !(component.isDelete == undefined ? false : component.isDelete)"
                            :key="index"
                        >
                            <component v-bind:is="parseView(component)" :detail="component" :editMode="true" :selected="selectedComponentMap[component.identifier] ? true : false" :ref="'comp' + index" />
                            <div>
                                <div class="rotate-text" v-show="rotateText && selectedComponentMap[component.identifier]">
                                    <i class="el-icon-edit" style="color: #67c23a; margin-right: 5px"></i>
                                    {{ component.style.transform }}°
                                </div>
                                <div class="rotate-icon" ref="rotateIcon" @mousedown.stop="mousedownAngle(component, index)" v-show="selectedComponentMap[component.identifier]">&#x21bb;</div>
                                <div @mousedown.stop="resizeMousedown(component, $event, index, 'resize-lt')" v-show="selectedComponentMap[component.identifier]" class="resize-left-top"></div>
                                <div @mousedown.stop="resizeMousedown(component, $event, index, 'resize-lc')" v-show="selectedComponentMap[component.identifier]" class="resize-left-center"></div>
                                <div @mousedown.stop="resizeMousedown(component, $event, index, 'resize-lb')" v-show="selectedComponentMap[component.identifier]" class="resize-left-bottom"></div>
                                <div @mousedown.stop="resizeMousedown(component, $event, index, 'resize-rt')" v-show="selectedComponentMap[component.identifier]" class="resize-right-top"></div>
                                <div @mousedown.stop="resizeMousedown(component, $event, index, 'resize-rc')" v-show="selectedComponentMap[component.identifier]" class="resize-right-center"></div>
                                <div @mousedown.stop="resizeMousedown(component, $event, index, 'resize-rb')" v-show="selectedComponentMap[component.identifier]" class="resize-right-bottom"></div>
                                <div @mousedown.stop="resizeMousedown(component, $event, index, 'resize-ct')" v-show="selectedComponentMap[component.identifier]" class="resize-center-top"></div>
                                <div @mousedown.stop="resizeMousedown(component, $event, index, 'resize-cb')" v-show="selectedComponentMap[component.identifier]" class="resize-center-bottom"></div>
                            </div>
                        </div>
                    </template>
                    <!-- 点开空白选中多个组件 -->
                    <div
                        class="topo-frame-selection"
                        :style="{ width: frameSelectionDiv.width + 'px', height: frameSelectionDiv.height + 'px', top: frameSelectionDiv.top + 'px', left: frameSelectionDiv.left + 'px' }"
                    ></div>
                </div>
                <!--放大缩小按钮-->
            </vue-ruler-tool>
        </div>
        <!--图层多页签-->
        <!--        <div style="height: 40px;border-top: #ccc solid 1px;position:relative;background-color:white;">-->
        <!--            <div style="position:absolute;left: 0px;top: 0px;" class="row">-->
        <!--                <div style="line-height:40px;height:40px;max-width: 65vw;">-->
        <!--                    <el-tabs v-model="activeName" type="card" @tab-click="handleClick">-->
        <!--                        <el-tab-pane :label="page.pageName" :name="page.guid" v-for="page in ztOption" :key="page.id">-->
        <!--                            <el-dropdown slot="label" @command="handleCommand">-->
        <!--                                <span :class="activeName == page.guid ? 'el-dropdown-link' : ''"><i-->
        <!--                                    class="el-icon-date"-->
        <!--                                ></i> {{-->
        <!--                                        page.pageName-->
        <!--                                    }}</span>-->
        <!--                                <el-dropdown-menu slot="dropdown">-->
        <!--                                    <el-dropdown-item :command="{ type: 'rename', page: page }">重命名-->
        <!--                                    </el-dropdown-item>-->
        <!--                                    <el-dropdown-item :command="{ type: 'delete', page: page }">删除</el-dropdown-item>-->
        <!--                                </el-dropdown-menu>-->
        <!--                            </el-dropdown>-->
        <!--                        </el-tab-pane>-->
        <!--                    </el-tabs>-->
        <!--                </div>-->
        <!--                <i class="el-icon-plus avatar-uploader-icon" @click="addZtPage"></i>-->
        <!--            </div>-->
        <!--        </div>-->
        <el-dialog
            :title="uploadImport.title"
            :visible.sync="uploadImport.open"
            width="400px"
            :close-on-click-modal="false"
            append-to-body
            v-loading="importLoading"
            element-loading-text="拼命导入中"
            element-loading-spinner="el-icon-loading"
            element-loading-background="rgba(0, 0, 0, 0.8)"
        >
            <el-upload
                ref="uploadImport"
                :limit="1"
                accept=".json"
                :headers="uploadImport.headers"
                :action="uploadImport.url"
                :disabled="uploadImport.isUploading"
                :on-progress="handleFileUploadProgress"
                :on-success="handleFileSuccess"
                :auto-upload="false"
                drag
            >
                <i class="el-icon-upload"></i>
                <div class="el-upload__text">
                    将文件拖到此处，或
                    <em>点击上传</em>
                </div>
                <div class="el-upload__tip" style="color: red" slot="tip">提示：仅允许导入“Json”格式文件！</div>
                <div class="el-upload__tip" style="color: red" slot="tip">提示：导入界面后需重新绑定设备参数！</div>
            </el-upload>
            <div slot="footer" class="dialog-footer">
                <el-button type="primary" @click="submitFileForm">确 定</el-button>
                <el-button @click="uploadImport.open = false">取 消</el-button>
            </div>
        </el-dialog>
        <el-dialog title="重命名" :visible.sync="dialogVisibleRename" width="20%" :close-on-click-modal="false" append-to-body>
            <el-input v-model="renameValue" placeholder="请输入内容"></el-input>
            <span slot="footer" class="dialog-footer">
                <el-button @click="dialogVisibleRename = false">取 消</el-button>
                <el-button type="primary" @click="submitRename">确 定</el-button>
            </span>
        </el-dialog>
    </div>
</template>

<script>
import VueRulerTool from '@/views/zutai/components/topo/ruler';
import TopoBase from './TopoBase';

import uid from '@/views/zutai/api/zutai/uid.js';

import topoUtil from '@/views/zutai/components/topo/util/topo-util.js';
import { deepCopy } from '@/views/zutai/api/zutai/utils';

import { checkInRange, checkByPointInRect, checkByRectCollisionDetection } from '@/views/zutai/api/zutai/topo';

import { mapActions, mapState, mapMutations } from 'vuex';
import request from '@/utils/request';
import Vue from 'vue';
import Contextmenu from 'vue-contextmenujs';

Vue.use(Contextmenu);
import FileSaver from 'file-saver';
import { toPng } from 'html-to-image';

export default {
    name: 'TopoMain',
    extends: TopoBase,
    components: {
        VueRulerTool,
    },
    props: [],
    computed: {
        ...mapState({
            selectedComponents: (state) => state.topoEditor.selectedComponents,
            selectedComponentMap: (state) => state.topoEditor.selectedComponentMap,
            configData: (state) => state.topoEditor.topoData,
            selectedIsLayer: (state) => state.topoEditor.selectedIsLayer,
            copySrcItems: (state) => state.topoEditor.copySrcItems,
            copyCount: (state) => state.topoEditor.copyCount,
            historyData: (state) => state.topoEditor.historyData,
            historyDataMark: (state) => state.topoEditor.historyDataMark,
        }),
        layerStyle: function () {
            // var scale = this.selectedValue / 100;

            let scale = this.selectedValue / 100;
            if (this.scale > 1) {
                scale = (this.selectedValue / 100) * this.scale;
            } else if (this.selectedValue == 100) {
                scale = '0.635,0.75';
            }
            var styles = [`transform:scale(${scale})`];
            styles.push(`transition: transform 1s ease-in-out`);
            if (this.configData.layer.backColor) {
                styles.push(`background-color: ${this.configData.layer.backColor}`);
            }
            if (this.configData.layer.backgroundImage) {
                styles.push(`background-image: url("${this.configData.layer.backgroundImage}")`);
            }
            if (this.configData.layer.width > 0) {
                styles.push(`width: ${this.configData.layer.width}px`);
            }
            if (this.configData.layer.height > 0) {
                styles.push(`height: ${this.configData.layer.height}px`);
            }
            if (this.$refs.imageTofile) {
                const topoMainHeight = Math.floor(this.$refs.topoMainRef.offsetHeight);
                const topoLayerHeight = Math.floor(this.$refs.imageTofile.offsetHeight * scale);
                // 86 原本的空隙,如果都减去后差值大于0,重新计算垂直居中的举例
                if (topoMainHeight - 86 - topoLayerHeight > 0) {
                    const marginT = (topoMainHeight - 38 - topoLayerHeight) / 2;
                    styles.push(`marginTop: ${marginT}px`);
                }
            }
            styles.push('overflow:hidden');
            var style = styles.join(';');
            return style;
        },
    },
    data() {
        return {
            scale: 1,
            moveItem: {
                startX: 0,
                startY: 0,
            }, //移动组件 相关变量
            resizeItem: {
                startPx: 0,
                startPy: 0,
                x: 0,
                y: 0,
                w: 0,
                h: 0,
            }, //resize组件 相关变量
            frameSelectionDiv: {
                width: 0,
                height: 0,
                top: 10,
                left: 10,
                startX: 0,
                startY: 0,
                startPageX: 0,
                startPageY: 0,
            },
            flag: '', //当前操作标志位
            curControl: null,
            curIndex: -1,
            selectedValue: 100,
            currentData: '',
            isFullFlag: false,
            selectComponent: null,
            selectIndx: null,
            activeName: this.$route.query.guid,
            ztOption: [],
            ztGuid: this.$route.query.guid,
            uploadImport: {
                // 是否显示弹出层（用户导入）
                open: false,
                // 弹出层标题（用户导入）
                title: '',
                // 是否禁用上传
                isUploading: false,
                // 是否更新已经存在的用户数据
                updateSupport: 0,
                // 设置上传的请求头部
                headers: { Authorization: 'Bearer ' + sessionStorage.getItem('Admin-Token-WebTopo') },
                // 上传的地址
                url: '',
            },
            importLoading: false,
            deviceZtRow: {},
            isMultiple: false,
            newestConfigData: null,
            dialogVisibleRename: false,
            renameValue: '',
            renameId: null,
            isLock: false,
            startingMouseAngle: 0,
            startingRotation: 0,
            rotateText: false,
        };
    },
    mounted() {
        //crtl+s保存数据
        document.addEventListener('keydown', this.saveContent, false);
        window.onbeforeunload = function (e) {
            return '';
        };
        this.getZtData();
        this.getZtPage();
        this.handleView('自适应');
    },
    methods: {
        //旋转
        mousedownAngle(curControl, curIndex) {
            let rotateDiv = this.$refs['comp' + curIndex][0].$el;
            const rect = rotateDiv.getBoundingClientRect();
            const centerX = rect.left + rect.width / 2;
            const centerY = rect.top + rect.height / 2;
            this.startingMouseAngle = this.getAngle(centerX, centerY, event.clientX, event.clientY);
            this.startingRotation = curControl.style.transform;
            window.addEventListener('mousemove', this.spin);
            window.addEventListener('mouseup', this.stopSpin);
            this.rotateText = true;
        },
        spin(event) {
            this.rotateText = true;
            let rotateDiv = this.$refs['comp' + this.curIndex][0].$el;
            const rect = rotateDiv.getBoundingClientRect();
            const centerX = rect.left + rect.width / 2;
            const centerY = rect.top + rect.height / 2;
            const currentMouseAngle = this.getAngle(centerX, centerY, event.clientX, event.clientY);
            const deltaMouseAngle = currentMouseAngle - this.startingMouseAngle;
            let newRotation = this.startingRotation + deltaMouseAngle;
            newRotation = parseInt(this.normalizeRotation(newRotation));
            this.$emit('handelAngel', newRotation);
        },
        stopSpin() {
            window.removeEventListener('mousemove', this.spin);
            window.removeEventListener('mouseup', this.stopSpin);
            this.rotateText = false;
        },
        normalizeRotation(rotation) {
            if (rotation >= 0) {
                return rotation % 360;
            } else {
                return (rotation % 360) + 360;
            }
        },
        getAngle(centerX, centerY, mouseX, mouseY) {
            return Math.atan2(mouseY - centerY, mouseX - centerX) * (180 / Math.PI);
        },
        //格式刷
        handleBrush() {
            if (this.selectedComponents.length < 2) {
                return;
            }
            let defaultStyle = this.selectedComponentMap[this.selectedComponents[0]].style;
            this.configData.components.forEach((element) => {
                if (this.selectedComponents[0] != element.identifier && this.selectedComponentMap[element.identifier]) {
                    let x = element.style.position.x;
                    let y = element.style.position.y;
                    let imageUrl = element.style.url;
                    element.style = deepCopy(defaultStyle);
                    element.style.position.x = x;
                    element.style.position.y = y;
                    element.style.url = imageUrl;
                }
            });
        },
        htmlToImage() {
            toPng(this.$refs.imageTofile)
                .then((dataUrl) => {
                    let data = {
                        guid: this.ztGuid,
                        base64: dataUrl,
                    };
                    let url = '/zutai/bDeviceZt/saveZtImage';
                    request({
                        url: url,
                        method: 'post',
                        data: data,
                    });
                })
                .catch((error) => {
                    console.error('oops, something went wrong!', error);
                });
        },
        //初始化卡尺
        initRuler() {
            this.$refs.rulerTool.init();
        },
        //
        handleCommand(command) {
            console.log(command);
            if (command.type == 'update') {
                this.activeName = command.page.guid;
                this.handleClick();
            } else if (command.type == 'rename') {
                this.dialogVisibleRename = true;
                this.renameValue = command.page.pageName;
                this.renameId = command.page.id;
            } else if (command.type == 'delete') {
                this.$confirm('您确定要删除此页面，删除之后不可恢复！！！', '提示', {
                    confirmButtonText: '删除',
                    cancelButtonText: '取消',
                    type: 'warning',
                })
                    .then(() => {
                        let url = '/zutai/bDeviceZt/' + command.page.id;
                        request({
                            url: url,
                            method: 'delete',
                        }).then((res) => {
                            this.getZtPage('初始化');
                        });
                    })
                    .catch(() => {});
            }
        },
        submitRename() {
            let data = {
                id: this.renameId,
                pageName: this.renameValue,
            };
            let url = '/zutai/bDeviceZt';
            request({
                url: url,
                method: 'put',
                data: data,
            }).then((res) => {
                // console.log('保存成功!',res);
                this.dialogVisibleRename = false;
                this.getZtPage();
            });
        },
        //调整视图
        handleView(value) {
            let rate = (this.$refs.topoMain.clientWidth - 48) / this.configData.layer.width - 0.01;
            if (value == '自适应') {
                this.selectedValue = rate * 100;
            } else {
                this.selectedValue = parseInt(value);
            }
            // console.log('当前缩放',this.selectedValue);
        },
        //导入组态json
        handleImport() {
            this.uploadImport.title = '组态导入';
            this.uploadImport.open = true;
            this.uploadImport.url = '/zutai/bDeviceZt/importZtJson?deviceImei=' + this.$route.query.deviceImei + '&guid=' + this.ztGuid;
        },
        // 文件上传中处理
        handleFileUploadProgress(event, file, fileList) {
            this.uploadImport.isUploading = true;
        },
        // 文件上传成功处理
        handleFileSuccess(response, file, fileList) {
            this.uploadImport.open = false;
            this.uploadImport.isUploading = false;
            this.$refs.uploadImport.clearFiles();
            this.$alert(response.msg, '导入结果', { dangerouslyUseHTMLString: true });
            this.importLoading = false;
            this.getZtData();
        },
        // 提交上传文件
        submitFileForm() {
            this.$refs.uploadImport.submit();
            this.importLoading = true;
        },
        //导出组态json
        handleDownLoad() {
            const data = JSON.stringify(this.deviceZtRow);
            const blob = new Blob([data], { type: '' });
            FileSaver.saveAs(blob, document.title + '.json');
        },
        //撤销
        revoke() {
            let historyDataMark = this.historyDataMark;
            historyDataMark = historyDataMark - 1;
            if (historyDataMark < 0) {
                historyDataMark = 0;
            }
            let configData = this.historyData[historyDataMark];
            console.log(configData, historyDataMark, this.historyData);
            this.loadDefaultTopoData(configData);
            this.setHistoryDataMark(historyDataMark);
        },
        //恢复
        recovery() {
            let historyDataMark = this.historyDataMark;
            historyDataMark = historyDataMark + 1;
            if (historyDataMark >= this.historyData.length) {
                historyDataMark = this.historyData.length - 1;
            }
            let configData = this.historyData[historyDataMark];
            console.log(configData, historyDataMark, this.historyData);
            this.loadDefaultTopoData(configData);
            this.setHistoryDataMark(historyDataMark);
        },
        onTabContextmenu(event) {
            console.log('右键', this.activeName);
            this.$contextmenu({
                items: [
                    {
                        label: '全屏',
                        icon: 'el-icon-full-screen',
                        onClick: () => {
                            this.clickFullscreen();
                        },
                    },
                    {
                        label: '重新加载',
                        divided: true,
                        icon: 'el-icon-refresh',
                        onClick: () => {
                            this.$router.go(0);
                        },
                    },
                ],
                event, // 鼠标事件信息
                customClass: 'custom-class', // 自定义菜单 class
                zIndex: 9999, // 菜单样式 z-index
                minWidth: 230, // 主菜单最小宽度
            });

            return true;
        },
        onContextmenu(event) {
            if (this.selectedComponentMap && this.selectedComponentMap[this.selectedComponents].type == 'VR') {
                return;
            }
            let isDisabled = false;
            if (this.selectedComponents.length > 0) {
                isDisabled = false;
            } else {
                isDisabled = true;
            }

            // console.log(isDisabled);
            let that = this;
            this.$contextmenu({
                items: [
                    {
                        label: '取消',
                        icon: 'el-icon-circle-close',
                        onClick: () => {},
                    },
                    {
                        label: '复制',
                        icon: 'el-icon-document-copy',
                        disabled: isDisabled,
                        onClick: () => {
                            that.copyItem();
                            that.pasteItem();
                        },
                    },
                    {
                        label: '删除',
                        icon: 'el-icon-delete',
                        disabled: isDisabled,
                        onClick: () => {
                            that.removeItem();
                        },
                    },
                    {
                        label: '置顶',
                        icon: 'el-icon-top',
                        disabled: isDisabled,
                        onClick: () => {
                            that.$emit('menuClick', '置顶');
                        },
                    },
                    {
                        label: '置底',
                        icon: 'el-icon-bottom',
                        disabled: isDisabled,
                        onClick: () => {
                            that.$emit('menuClick', '置底');
                        },
                    },
                    {
                        label: '旋转',
                        minWidth: 0,
                        disabled: isDisabled,
                        children: [
                            {
                                label: '顺时针90°',
                                icon: 'el-icon-plus',
                                onClick: () => {
                                    // console.log("顺时针90°");
                                    that.$emit('menuClick', '顺时针90°');
                                },
                            },
                            {
                                label: '逆时针90°',
                                icon: 'el-icon-minus',
                                onClick: () => {
                                    // console.log("逆时针90°");
                                    that.$emit('menuClick', '逆时针90°');
                                },
                            },
                            {
                                label: '水平镜像',
                                icon: 'el-icon-d-arrow-left',
                                onClick: () => {
                                    // console.log("水平镜像");
                                    that.$emit('menuClick', '水平镜像');
                                },
                            },
                            {
                                label: '垂直镜像',
                                icon: 'el-icon-d-arrow-right',
                                onClick: () => {
                                    // console.log("垂直镜像");
                                    that.$emit('menuClick', '垂直镜像');
                                },
                            },
                            {
                                label: '自定义角度',
                                icon: 'el-icon-edit',
                                onClick: () => {
                                    // console.log("自定义角度");
                                    that.$emit('menuClick', '自定义角度');
                                },
                            },
                        ],
                    },
                    {
                        label: '对齐',
                        minWidth: 0,
                        disabled: isDisabled,
                        children: [
                            {
                                label: '左对齐',
                                icon: 'el-icon-arrow-left',
                                onClick: () => {
                                    that.alignClick('左对齐');
                                },
                            },
                            {
                                label: '右对齐',
                                icon: 'el-icon-arrow-right',
                                onClick: () => {
                                    that.alignClick('右对齐');
                                },
                            },
                            {
                                label: '上对齐',
                                icon: 'el-icon-arrow-up',
                                onClick: () => {
                                    that.alignClick('上对齐');
                                },
                            },
                            {
                                label: '下对齐',
                                icon: 'el-icon-arrow-down',
                                onClick: () => {
                                    that.alignClick('下对齐');
                                },
                            },
                            {
                                label: '水平等间距',
                                icon: 'el-icon-sort',
                                onClick: () => {
                                    that.alignClick('水平等间距');
                                },
                            },
                            {
                                label: '垂直等间距',
                                icon: 'el-icon-sort',
                                onClick: () => {
                                    that.alignClick('垂直等间距');
                                },
                            },
                        ],
                    },
                    {
                        label: '组合',
                        minWidth: 0,
                        disabled: isDisabled,
                        children: [
                            {
                                label: '组合',
                                icon: 'el-icon-connection',
                                onClick: () => {
                                    that.makeUpClick('组合');
                                },
                            },
                            {
                                label: '取消组合',
                                icon: 'el-icon-link',
                                onClick: () => {
                                    that.makeUpClick('取消组合');
                                },
                            },
                        ],
                    },
                    {
                        label: '锁定',
                        minWidth: 0,
                        disabled: isDisabled,
                        children: [
                            {
                                label: '锁定',
                                icon: 'el-icon-lock',
                                onClick: () => {
                                    that.handleLock('锁定');
                                },
                            },
                            {
                                label: '解锁',
                                icon: 'el-icon-unlock',
                                onClick: () => {
                                    that.handleLock('解锁');
                                },
                            },
                        ],
                    },
                    {
                        label: '图库',
                        divided: true,
                        icon: 'el-icon-picture-outline',
                        onClick: () => {
                            that.$emit('menuClick', '图库');
                        },
                    },
                    {
                        label: '预览',
                        divided: true,
                        icon: 'el-icon-view',
                        onClick: () => {
                            that.$emit('menuClick', '预览');
                        },
                    },
                    {
                        label: '保存',
                        divided: true,
                        icon: 'el-icon-star-off',
                        onClick: () => {
                            that.$emit('menuClick', '保存');
                        },
                    },
                    {
                        label: '重新加载',
                        divided: true,
                        icon: 'el-icon-refresh',
                        onClick: () => {
                            this.$router.go(0);
                        },
                    },
                ],
                event, // 鼠标事件信息
                customClass: 'custom-class', // 自定义菜单 class
                zIndex: 9999, // 菜单样式 z-index
                minWidth: 230, // 主菜单最小宽度
            });

            return true;
        },
        addZtPage() {
            let json = JSON.stringify({
                name: '--',
                layer: {
                    backColor: '',
                    backgroundImage: '',
                    widthHeightRatio: '',
                    width: 1920,
                    height: 1080,
                },
                components: [],
            });
            let data = {
                deviceMac: this.$route.query.deviceImei,
                isMainPage: 0,
                deviceName: this.$route.query.deviceName,
                pageName: '页面' + (this.ztOption.length + 1),
                pageSize: '1920x1080',
                deviceZtData: json,
            };
            let url = '/zutai/bDeviceZt';
            request({
                url: url,
                method: 'post',
                data: data,
            }).then((res) => {
                // this.showMessage('success',"新增成功")
                this.getZtPage('切换界面');
            });
        },
        getZtPage(val) {
            let query = {
                pageNum: 1,
                pageSize: 999,
                deviceMac: this.$route.query.deviceImei,
                orderByColumn: 'id',
                isAsc: 'asc',
            };
            let url = '/zutai/bDeviceZt/list';
            request({
                url: url,
                method: 'get',
                params: query,
            }).then((res) => {
                this.ztOption = res.rows;
                if (val) {
                    this.activeName = this.ztOption[this.ztOption.length - 1].guid;
                    this.handleClick();
                }
            });
        },
        handleClick(tab, event) {
            if (this.activeName == this.ztGuid) {
                return;
            }
            this.printData('组合');
            this.ztGuid = this.activeName;
            this.getZtData();
        },
        ...mapMutations('topoEditor', [
            'setSelectedComponent',
            'addSelectedComponent',
            'removeSelectedComponent',
            'clearSelectedComponent',
            'setLayerSelected',
            'setCopySrcItems',
            'increaseCopyCount',
            'execute',
            'undo',
            'redo',
            'setHistoryDataMark',
        ]),
        ...mapActions('topoEditor', ['loadDefaultTopoData']),
        controlMousedown(component, event, index) {
            if (event.ctrlKey) {
                return;
            }
            this.flag = 'move';
            this.curControl = component;
            this.curIndex = index;
            this.clickItem(component, index);
            this.moveItem.startX = event.pageX;
            this.moveItem.startY = event.pageY;
            //记录初始信息--move
            for (var key in this.selectedComponentMap) {
                var component = this.selectedComponentMap[key];
                component.style.temp = {};
                component.style.temp.position = {};
                component.style.temp.position.x = component.style.position.x;
                component.style.temp.position.y = component.style.position.y;
            }
        },
        resizeMousedown(component, event, index, flag) {
            //resize-鼠标按下事件
            this.flag = flag;
            this.curControl = component;
            this.curIndex = index;
            this.clickItem(component, index);
            // var dom = event.currentTarget;
            this.resizeItem.startPx = event.clientX;
            this.resizeItem.startPy = event.clientY;
            //记录初始信息-resize
            this.resizeItem.x = this.curControl.style.position.x;
            this.resizeItem.y = this.curControl.style.position.y;
            this.resizeItem.w = this.curControl.style.position.w;
            this.resizeItem.h = this.curControl.style.position.h;
        },
        onLayerMousemove(event) {
            if (event.which != 1) {
                this.flag = '';
                return;
            }
            if (this.flag == '') {
                return;
            }
            if (this.flag.startsWith('resize')) {
                var dx = event.clientX - this.resizeItem.startPx,
                    dy = event.clientY - this.resizeItem.startPy;
                switch (this.flag) {
                    case 'resize-lt':
                        this.curControl.style.position.x = this.resizeItem.x + dx;
                        this.curControl.style.position.y = this.resizeItem.y + dy;
                        dx = -dx;
                        dy = -dy;
                        break;
                    case 'resize-lc':
                        this.curControl.style.position.x = this.resizeItem.x + dx;
                        dy = 0;
                        dx = -dx;
                        break;
                    case 'resize-lb':
                        this.curControl.style.position.x = this.resizeItem.x + dx;
                        dx = -dx;
                        break;
                    case 'resize-rt':
                        this.curControl.style.position.y = this.resizeItem.y + dy;
                        dy = -dy;
                        break;
                    case 'resize-rc':
                        dy = 0;
                        break;
                    case 'resize-rb':
                        break;
                    case 'resize-ct':
                        this.curControl.style.position.y = this.resizeItem.y + dy;
                        dx = 0;
                        dy = -dy;
                        break;
                    case 'resize-cb':
                        dx = 0;
                        break;
                }
                if (this.resizeItem.w + dx > 20) {
                    this.curControl.style.position.w = this.resizeItem.w + dx;
                }
                if (this.resizeItem.h + dy > 20) {
                    this.curControl.style.position.h = this.resizeItem.h + dy;
                }
                //canvas组件需要重新渲染
                // DOM 还没有更新
                this.$nextTick(function () {
                    // DOM 更新了
                    var a = this.$refs['comp' + this.curIndex][0];
                    try {
                        a.onResize();
                    } catch {}
                });
            } else if (this.flag == 'move') {
                //移动组件
                var dx = event.pageX - this.moveItem.startX,
                    dy = event.pageY - this.moveItem.startY;
                for (var key in this.selectedComponentMap) {
                    var component = this.selectedComponentMap[key];
                    if (!component.isLock) {
                        if (this.selectedValue == 100) {
                            component.style.position.x = component.style.temp.position.x + dx;
                            component.style.position.y = component.style.temp.position.y + dy;
                        } else if (this.selectedValue > 100) {
                            component.style.position.x = component.style.temp.position.x + dx / (this.selectedValue / 100);
                            component.style.position.y = component.style.temp.position.y + dy / (this.selectedValue / 100);
                        } else {
                            component.style.position.x = component.style.temp.position.x + dx + dx * ((100 - this.selectedValue) / 100);
                            component.style.position.y = component.style.temp.position.y + dy + dy * ((100 - this.selectedValue) / 100);
                        }
                    }
                }
                //移动组件
            } else if (this.flag == 'frame_selection') {
                this.onFrameSelection(event);
            }
        },
        onLayerMouseup(event) {
            // console.log("组件回滚");
            if (this.flag.startsWith('resize')) {
                var a = this.$refs['comp' + this.curIndex][0];
                try {
                    a.onResize();
                } catch {}
            } else if (this.flag == 'frame_selection') {
                //由于和onLayerClick冲突，这里模拟下点击空白区域
                this.onFrameSelection(event);
                this.frameSelectionDiv.width = 0;
                this.frameSelectionDiv.height = 0;
                this.frameSelectionDiv.top = 0;
                this.frameSelectionDiv.left = 0;
            } else if (this.flag == 'move') {
                //鼠标move只是方便用户预览，真正执行应该用命令，所以要先恢复
                var dx = event.pageX - this.moveItem.startX;
                var dy = event.pageY - this.moveItem.startY;
                for (var key in this.selectedComponentMap) {
                    var component = this.selectedComponentMap[key];
                    component.style.position.x = component.style.position.x - dx;
                    component.style.position.y = component.style.position.y - dy;
                }
                this.execute({
                    op: 'move',
                    dx: dx,
                    dy: dy,
                    items: this.selectedComponentMap,
                });
            }
            this.flag = '';
        },
        onLayerMousedown(event) {
            this.flag = 'frame_selection';
            this.frameSelectionDiv.startX = event.offsetX;
            this.frameSelectionDiv.startY = event.offsetY;
            this.frameSelectionDiv.startPageX = event.pageX;
            this.frameSelectionDiv.startPageY = event.pageY;
            this.isMultiple = true;
        },
        onLayerClick() {
            if (this.isMultiple == false) {
                this.clearSelectedComponent();
                this.selectComponent = null;
            } else {
                this.isMultiple = false;
            }
            this.setLayerSelected(true);
        },
        onFrameSelection(event) {
            var dx = event.pageX - this.frameSelectionDiv.startPageX;
            var dy = event.pageY - this.frameSelectionDiv.startPageY;
            if (this.scale == 1) {
                this.frameSelectionDiv.width = Math.floor(Math.abs(dx) / 0.635);
                this.frameSelectionDiv.height = Math.floor(Math.abs(dy) / 0.75);
            } else {
                this.frameSelectionDiv.width = Math.floor(Math.abs(dx) / this.scale);
                this.frameSelectionDiv.height = Math.floor(Math.abs(dy) / this.scale);
            }
            this.frameSelectionDiv.top = event.pageY > this.frameSelectionDiv.startPageY ? this.frameSelectionDiv.startY : event.offsetY;
            this.frameSelectionDiv.left = event.pageX > this.frameSelectionDiv.startPageX ? this.frameSelectionDiv.startX : event.offsetX;
            //判断各个组件是否在方框内
            var _this = this;
            var rect = {
                x: this.frameSelectionDiv.left,
                y: this.frameSelectionDiv.top,
                width: this.frameSelectionDiv.width,
                height: this.frameSelectionDiv.height,
            };
            var components = this.configData.components;
            components.forEach((component) => {
                var itemRect = {
                    x: component.style.position.x,
                    y: component.style.position.y,
                    width: component.style.position.w,
                    height: component.style.position.h,
                };
                if (checkByRectCollisionDetection(rect, itemRect)) {
                    _this.addSelectedComponent(component);
                } else {
                    _this.removeSelectedComponent(component);
                }
            });
            if (this.selectedComponents.length > 0) {
                this.setLayerSelected(false);
            } else {
                this.setLayerSelected(true);
            }
        },
        onDrop(event) {
            event.preventDefault();
            var infoJson = event.dataTransfer.getData('my-info');
            var component = JSON.parse(infoJson);
            if (component.type == 'weather') {
                var components = this.configData.components;
                let isExist = false;
                components.forEach((component) => {
                    if (component.type == 'weather') {
                        isExist = true;
                    }
                });
                if (isExist) {
                    this.$message({
                        message: '天气组件已存在，不能重复添加',
                        type: 'warning',
                    });
                    return;
                }
            }
            if (this.checkAddComponent(component) == false) {
                return;
            }
            //判断当前着陆点是不是layer
            if (event.target.id == 'surface-edit-layer') {
                component.style.position.x = event.offsetX;
                component.style.position.y = event.offsetY;
            } else {
                //解决着陆灯不是layer的情形
                var layer = event.currentTarget;
                var position = layer.getBoundingClientRect();
                var x = event.clientX - position.left;
                var y = event.clientY - position.top;
                component.style.position.x = x;
                component.style.position.y = y;
            }
            //处理默认值
            this.execute({
                op: 'add',
                component: component,
            });

            //默认选中，并点击
            this.clickItem(component, this.configData.components.length - 1);
        },
        moveItems(direction) {
            var dx = 0,
                dy = 0;
            if (direction == 'up') {
                dy = -5;
            } else if (direction == 'right') {
                dx = 5;
            } else if (direction == 'down') {
                dy = 5;
            } else if (direction == 'left') {
                dx = -5;
            }
            this.execute({
                op: 'move',
                dx: dx,
                dy: dy,
                items: this.selectedComponentMap,
            });
        },
        checkAddComponent(info) {
            if (info == null) {
                this.$q.notify({
                    type: 'negative',
                    position: 'bottom-right',
                    message: 'This component not surpport.',
                });
                return false;
            }
            return true;
        },
        parseView(component) {
            return topoUtil.parseViewName(component);
        },
        clickItem(component, index) {
            this.selectComponent = component;
            this.selectIndx = index;
            this.setLayerSelected(false);
            if (this.selectedComponentMap[component.identifier] == undefined) {
                this.setSelectedComponent(component);
            } else if (component.identifiers && component.identifiers.indexOf(component.identifier) > -1) {
                this.setSelectedComponent(component);
            }
            this.$emit('lockStatus', component.isLock);
        },
        clickComponent(index, component, event) {
            //点击组件
            if (event.ctrlKey == true) {
                //点击了ctrl
                this.setLayerSelected(false);
                if (this.selectedComponentMap[component.identifier] == undefined) {
                    this.addSelectedComponent(component);
                } else {
                    this.removeSelectedComponent(component);
                }
            } else {
                //这里不再处理点击事件，改为鼠标左键
                //this.clickItem(component,index);
            }
        },
        copyItem() {
            // 设定复制源
            var items = [];
            for (var key in this.selectedComponentMap) {
                var item = deepCopy(this.selectedComponentMap[key]);
                items.push(item);
            }
            this.setCopySrcItems(items);
        },
        pasteItem() {
            // console.log("粘贴",this.copySrcItems);
            if (this.copySrcItems && this.copySrcItems.length > 0) {
                this.execute({
                    op: 'copy-add',
                    items: this.copySrcItems,
                });
            }
        },
        removeItem(event) {
            //移除组件
            if (event && event.code == 'Backspace') {
                return;
            }
            this.execute({
                op: 'del',
            });
            this.setLayerSelected(false);
            this.setLayerSelected(true);
        },
        fullScreen() {
            const routeUrl = this.$router.resolve({
                path: '/fullscreen',
                query: {
                    token: this.$route.query.accessToken,
                    guid: this.ztGuid,
                    deviceImei: this.$route.query.deviceImei,
                },
            });
            window.open(routeUrl.href, '_blank');
        },
        //保存组件数据详情
        printData(val) {
            //统一去除组件为isDelete的删除数据
            const configData = this.configData;
            for (var i = 0; i < configData.components.length; i++) {
                if (configData.components[i].isDelete) {
                    configData.components.splice(i, 1);
                    i--;
                }
            }
            var json = JSON.stringify(configData);
            this.currentData = json;
            let data = {
                guid: this.ztGuid,
                deviceMac: this.$route.query.deviceImei,
                deviceZtData: json,
            };
            let url = '/zutai/bDeviceZt/saveZt';
            request({
                url: url,
                method: 'post',
                data: data,
            }).then((res) => {
                // console.log('保存成功!',res);
                if (val != '组合') {
                    this.showMessage('success', '保存成功');
                }
                this.htmlToImage();
            });
        },
        getZtData() {
            let query = {
                deviceMac: this.$route.query.deviceImei,
                guid: this.ztGuid,
            };
            let url = '/zutai/bDeviceZt/getZtData';
            request({
                url: url,
                method: 'get',
                params: query,
            }).then((res) => {
                this.deviceZtRow = res.data;
                //修改title值
                document.title = this.deviceZtRow.pageName;
                if (this.deviceZtRow.deviceZtData) {
                    let configData = JSON.parse(this.deviceZtRow.deviceZtData);
                    console.log('组件JSON格式化', JSON.parse(this.deviceZtRow.deviceZtData));
                    configData.WebTopoGuid = this.$route.query.guid;
                    configData.WebTopoDeviceImei = this.$route.query.deviceImei;
                    this.loadDefaultTopoData(configData);
                } else {
                    let configData = {
                        name: '--',
                        layer: {
                            backColor: '',
                            backgroundImage: '',
                            widthHeightRatio: '',
                            width: 1920,
                            height: 1080,
                        },
                        components: [],
                    };
                    configData.WebTopoGuid = this.$route.query.guid;
                    configData.WebTopoDeviceImei = this.$route.query.deviceImei;
                    this.loadDefaultTopoData(configData);
                }
            });
        },
        showMessage(type, msg) {
            this.$message({
                message: msg,
                type: type,
                duration: 1500,
            });
        },
        //锁定/解锁
        handleLock(command) {
            // console.log(command);
            if (command == '锁定') {
                for (var key in this.selectedComponentMap) {
                    this.selectedComponentMap[key].isLock = true;
                }
                this.$emit('lockStatus', true);
            } else {
                for (var key in this.selectedComponentMap) {
                    this.selectedComponentMap[key].isLock = false;
                }
                this.$emit('lockStatus', false);
            }
            // console.log("组件总数据",this.configData);
            // this.printData();
        },
        //组件对齐  selectedComponents选中的组件的id数组  selectedComponentMap选中组件的全部内容
        alignClick(command) {
            if (command == '右对齐') {
                let alignX = 0;
                let alignComponent = null;
                this.selectedComponents.forEach((element) => {
                    var component = deepCopy(this.selectedComponentMap[element]);
                    if (component.style.position.x > alignX) {
                        alignX = component.style.position.x;
                        alignComponent = deepCopy(this.selectedComponentMap[element]);
                    }
                });
                for (var key in this.selectedComponentMap) {
                    if (this.selectedComponentMap[key].style.position.x != alignX) {
                        this.selectedComponentMap[key].style.position.x = alignX + alignComponent.style.position.w - this.selectedComponentMap[key].style.position.w;
                    }
                }
            } else if (command == '左对齐') {
                let alignX = 9999;
                this.selectedComponents.forEach((element) => {
                    var component = deepCopy(this.selectedComponentMap[element]);
                    if (component.style.position.x < alignX) {
                        alignX = component.style.position.x;
                    }
                });
                for (var key in this.selectedComponentMap) {
                    this.selectedComponentMap[key].style.position.x = alignX;
                }
            } else if (command == '上对齐') {
                let alignY = 9999;
                this.selectedComponents.forEach((element) => {
                    var component = deepCopy(this.selectedComponentMap[element]);
                    if (component.style.position.y < alignY) {
                        alignY = component.style.position.y;
                    }
                });
                for (var key in this.selectedComponentMap) {
                    this.selectedComponentMap[key].style.position.y = alignY;
                }
            } else if (command == '下对齐') {
                let alignY = 0;
                let alignYBottom = 0;
                this.selectedComponents.forEach((element) => {
                    var component = deepCopy(this.selectedComponentMap[element]);
                    if (component.style.position.y > alignY) {
                        alignY = component.style.position.y;
                        alignYBottom = alignY + component.style.position.h;
                    }
                });
                console.log('alignYBottom', alignYBottom);
                for (var key in this.selectedComponentMap) {
                    this.selectedComponentMap[key].style.position.y = alignYBottom - this.selectedComponentMap[key].style.position.h;
                }
            } else if (command == '水平等间距') {
                let distance = 0;
                let oneX = 0;
                let twoX = 0;
                let oneWidth = 0;
                this.selectedComponents.forEach((element, index) => {
                    var component = deepCopy(this.selectedComponentMap[element]);
                    if (index == 0) {
                        oneX = component.style.position.x;
                        oneWidth = component.style.position.w;
                    }
                    if (index == 1) {
                        twoX = component.style.position.x;
                    }
                });
                distance = twoX - oneX - oneWidth;
                for (var key in this.selectedComponentMap) {
                    if (distance > 0) {
                        this.selectedComponentMap[key].style.position.x = oneX;
                        oneX = oneX + distance + this.selectedComponentMap[key].style.position.w;
                    }
                }
                //this.printData();
            } else if (command == '垂直等间距') {
                let distance = 0;
                let oneY = 0;
                let twoY = 0;
                let oneHeight = 0;
                this.selectedComponents.forEach((element, index) => {
                    var component = deepCopy(this.selectedComponentMap[element]);
                    if (index == 0) {
                        oneY = component.style.position.y;
                        oneHeight = component.style.position.h;
                    }
                    if (index == 1) {
                        twoY = component.style.position.y;
                    }
                });
                distance = twoY - oneY - oneHeight;
                for (var key in this.selectedComponentMap) {
                    if (distance > 0) {
                        this.selectedComponentMap[key].style.position.y = oneY;
                        oneY = oneY + distance + this.selectedComponentMap[key].style.position.h;
                    }
                }
                // this.printData();
            }
        },
        //组件组合
        makeUpClick(command) {
            if (command == '组合') {
                let identifiers = [];
                for (var key in this.selectedComponentMap) {
                    identifiers.push(key);
                }
                for (var key in this.selectedComponentMap) {
                    this.selectedComponentMap[key].identifiers = identifiers;
                }
            } else {
                for (var key in this.selectedComponentMap) {
                    this.selectedComponentMap[key].identifiers = [];
                }
            }
            if (this.selectedComponents.length == 0) {
                this.showMessage('warning', '未选中组合组件');
            } else {
                this.clearSelectedComponent();
                this.clickItem(this.selectComponent, this.selectIndx);
            }
        },
        saveContent(e) {
            var key = window.event.keyCode ? window.event.keyCode : window.event.which;
            if (key === 83 && e.ctrlKey) {
                e.preventDefault();
                this.printData();
            }
        },
        getJsonItem(url) {
            let newJson = {
                type: 'image',
                componentShow: ['动画', '单击', '组件颜色', '滤镜渲染', '组件填充', '参数绑定'],
                action: [],
                hdClassName: '',
                identifier: uid(),
                dataBind: {
                    queryParam: {},
                    imei: '',
                    paramField: '',
                    paramName: '',
                    driveName: '',
                    action: '',
                    paramValue: '',
                    redirectUrl: '',
                    stateList: [],
                },
                dataAction: {
                    //动作判断字段
                    imei: '',
                    paramField: '',
                    paramName: '',
                    paramJudge: '',
                    paramJudgeData: '',
                    rotationSpeed: '中',
                    translateList: [],
                },
                style: {
                    position: {
                        x: 200 + this.randomNumBoth(0, 30),
                        y: 200 + this.randomNumBoth(0, 30),
                        w: 100,
                        h: 100,
                    },
                    backColor: 'transparent',
                    foreColor: '',
                    zIndex: 1,
                    transform: 0,
                    url: url,
                    transformType: 'rotate(0deg)',
                    isFilter: true,
                    visible: true,
                },
            };
            return newJson;
        },
        randomNumBoth(Min, Max) {
            var Range = Max - Min;
            var Rand = Math.random();
            var num = Min + Math.round(Rand * Range); //四舍五入
            return num;
        },
        // 从图库添加组态图片
        addImageData(url) {
            let data = this.getJsonItem(url);
            this.configData.components.push(data);
        },
    },
    beforeDestroy() {
        document.removeEventListener('keydown', this.saveContent, false);
        window.onbeforeunload = null;
    },
    beforeRouteLeave(to, from, next) {
        if (this.progressVisible) {
            this.$confirm('系统可能不会保存您所做的更改。', '离开此页面？', {
                confirmButtonText: '离开',
                cancelButtonText: '取消',
                type: 'warning',
            }).then(() => {
                next();
            });
        } else {
            next();
        }
    },
};
</script>

<style lang="scss" scoped>
.scale-button {
    position: absolute;
    right: 20px;
    bottom: 20px;
    z-index: 1000;
}
.topo-main {
    background-color: #f0f2f5;
    background-image: radial-gradient(circle, #c2d3fa 1px, transparent 1px);
    background-size: 20px 20px;
    position: relative;
    overflow-x: hidden;
    overflow-y: hidden;
    width: 100%;
    height: 100%;

    .topo-main-header {
        width: 100%;
        height: calc(100vh - 61px);
        overflow-x: auto;
        overflow-y: auto;
    }

    .topo-layer {
        width: 100%;
        height: 100%;
        position: absolute;
        transform-origin: left top;
        overflow: auto;
        background-color: #ffffff;
        background-clip: padding-box;
        background-origin: padding-box;
        background-repeat: no-repeat;
        background-size: 100% 100%;
        margin: 24px;
        //box-shadow: 10px 15px 15px 8px #666666;//X轴、Y轴、模糊距离、阴影范围
        box-shadow: 0 0 12px 0 #0000001f; //X轴、Y轴、模糊距离、阴影范围

        .topo-frame-selection {
            background-color: #8787e7;
            opacity: 0.3;
            border: #0000ff solid 1px;
            position: absolute;
            z-index: 99999;
        }

        .topo-layer-view-selected-line {
            outline: 1px solid #0cf;
        }

        .topo-layer-view {
            position: absolute;
            height: 100px;
            width: 100px;
            background-color: #999;
            cursor: move;
            // border: #ccc solid 1px;

            .resize-left-top {
                position: absolute;
                height: 10px;
                width: 10px;
                border-radius: 50%;
                background-color: #fff;
                border: 1px solid #0cf;
                left: -5px;
                top: -5px;
                cursor: nwse-resize;
            }

            .resize-left-center {
                position: absolute;
                height: 10px;
                width: 10px;
                border-radius: 50%;
                background-color: #fff;
                border: 1px solid #0cf;
                left: -5px;
                top: 50%;
                margin-top: -5px;
                cursor: ew-resize;
            }

            .resize-left-bottom {
                position: absolute;
                height: 10px;
                width: 10px;
                border-radius: 50%;
                background-color: #fff;
                border: 1px solid #0cf;
                left: -5px;
                bottom: -5px;
                cursor: nesw-resize;
            }

            .resize-right-top {
                position: absolute;
                height: 10px;
                width: 10px;
                border-radius: 50%;
                background-color: #fff;
                border: 1px solid #0cf;
                right: -5px;
                top: -5px;
                cursor: nesw-resize;
            }

            .resize-right-center {
                position: absolute;
                height: 10px;
                width: 10px;
                border-radius: 50%;
                background-color: #fff;
                border: 1px solid #0cf;
                right: -5px;
                top: 50%;
                margin-top: -5px;
                cursor: ew-resize;
            }

            .resize-right-bottom {
                position: absolute;
                height: 10px;
                width: 10px;
                border-radius: 50%;
                background-color: #fff;
                border: 1px solid #0cf;
                right: -5px;
                bottom: -5px;
                cursor: nwse-resize;
            }

            .resize-center-top {
                position: absolute;
                height: 10px;
                width: 10px;
                border-radius: 50%;
                background-color: #fff;
                border: 1px solid #0cf;
                top: -5px;
                left: 50%;
                margin-left: -5px;
                cursor: ns-resize;
            }

            .resize-center-bottom {
                position: absolute;
                height: 10px;
                width: 10px;
                border-radius: 50%;
                background-color: #fff;
                border: 1px solid #0cf;
                bottom: -5px;
                left: 50%;
                margin-left: -5px;
                cursor: ns-resize;
            }
        }

        .topo-layer-view-selected {
            border: 1.5px solid #21cc96;
        }

        .topo-layer-view-selected:hover {
            border: 1.5px dashed #21cc96;
        }
    }

    .topo-layer::before,
    .topo-layer::after {
        position: fixed;
        top: 0;
        left: 0;
        right: 0;
        bottom: 0;
        content: '';
        background-repeat: repeat;
        pointer-events: none;
    }

    .topo-layer::before {
        /* background-image: linear-gradient(to right, black 1px, transparent 1px, transparent 10px), linear-gradient(to bottom, black 1px, transparent 1px, transparent 10px); */
        background-size: 10px 10px;
        opacity: 0.05;
    }

    .topo-layer::after {
        /* background-image: linear-gradient(to right, black 1px, transparent 1px, transparent 50px), linear-gradient(to bottom, black 1px, transparent 1px, transparent 50px); */
        background-size: 50px 50px;
        opacity: 0.1;
    }
}
</style>
<style scoped>
.avatar-uploader-icon {
    font-size: 20px;
    color: #78797a;
    width: 30px;
    height: 30px;
    font-weight: 700;
    line-height: 40px;
    margin-top: 2px;
    text-align: center;
}

.custom-class .menu_item__available:hover,
.custom-class .menu_item_expand {
    background: #ffecf2 !important;
    color: #ff4050 !important;
}

.el-dropdown-link {
    cursor: pointer;
    color: #409eff;
}
</style>
<style>
::-webkit-scrollbar-thumb {
    background-color: #e1e1e1;
}

::-webkit-scrollbar-thumb:hover {
    background-color: #a5a2a2;
}

::-webkit-scrollbar {
    width: 5px;
    height: 5px;
    position: absolute;
}

::-webkit-scrollbar-track {
    background-color: #fff;
}

.rotate-icon {
    position: absolute;
    top: -50px;
    /* 调整图标的位置 */
    left: 50%;
    transform: translateX(-50%);
    font-size: 25px;
    cursor: pointer;
    color: #67c23a;
}

.rotate-text {
    position: absolute;
    top: -70px;
    /* 调整图标的位置 */
    left: 55%;
    background: #909399;
    width: 60px;
    height: 30px;
    padding: 5px;
    color: #fff;
    opacity: 0.8;
}
</style>
